{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "\"\"\"\n",
    "BP神经网络\n",
    "\"\"\"\n",
    "import numpy as np\n",
    "import math\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "# 激励函数及相应导数\n",
    "def sigmoid(x):\n",
    "    return 1.0 / (1 + np.exp(-x))\n",
    "\n",
    "\n",
    "def diff_sigmoid(x):\n",
    "    fval = sigmoid(x)\n",
    "    return fval * (1 - fval)\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class BP:\n",
    "    def __init__(self, n_hidden=None, \n",
    "                 epsilon=1e-3, maxstep=1000, eta=0.01, alpha=0.0):\n",
    "        self.n_input = None  # 输入层神经元数目\n",
    "        self.n_hidden = n_hidden  # 隐藏层神经元数目\n",
    "        self.n_output = None\n",
    "        self.epsilon = epsilon\n",
    "        self.maxstep = maxstep\n",
    "        self.eta = eta  # 学习率\n",
    "        self.alpha = alpha  # 动量因子\n",
    "\n",
    "        self.wih = None  # 输入层到隐藏层权值矩阵\n",
    "        self.who = None  # 隐藏层到输出层权值矩阵\n",
    "        self.bih = None  # 输入层到隐藏层阈值\n",
    "        self.bho = None  # 隐藏层到输出层阈值\n",
    "        self.N = None\n",
    "\n",
    "    def init_param(self, X_data, y_data):\n",
    "        # 初始化\n",
    "        if len(X_data.shape) == 1:  # 若输入数据为一维数组，则进行转置为n维数组\n",
    "            X_data = np.transpose([X_data])\n",
    "        self.N = X_data.shape[0]\n",
    "        # normalizer = np.linalg.norm(X_data, axis=0)\n",
    "        # X_data = X_data / normalizer\n",
    "        if len(y_data.shape) == 1:\n",
    "            y_data = np.transpose([y_data])\n",
    "        self.n_input = X_data.shape[1]\n",
    "        self.n_output = y_data.shape[1]\n",
    "        if self.n_hidden is None:\n",
    "            self.n_hidden = int(math.ceil(math.sqrt(self.n_input + self.n_output)) + 2)\n",
    "        self.wih = np.random.rand(self.n_input, self.n_hidden)  # i*h\n",
    "        self.who = np.random.rand(self.n_hidden, self.n_output)  # h*o\n",
    "        self.bih = np.random.rand(self.n_hidden)  # h\n",
    "        self.bho = np.random.rand(self.n_output)  # o\n",
    "        return X_data, y_data\n",
    "\n",
    "    \n",
    "       \n",
    "    def forward(self, X_data):\n",
    "        # 前向传播\n",
    "        x_hidden_in = X_data @ self.wih + self.bih  # n*h   @来替代matmul\n",
    "        x_hidden_out = sigmoid(x_hidden_in)  # n*h\n",
    "        x_output_in = x_hidden_out @ self.who + self.bho  # n*o\n",
    "        x_output_out = sigmoid(x_output_in)  # n*o\n",
    "        return x_output_out, x_output_in, x_hidden_out, x_hidden_in\n",
    "\n",
    "    def fit(self, X_data, y_data):\n",
    "        # 训练主函数\n",
    "        X_data, y_data = self.init_param(X_data, y_data)\n",
    "        step = 0\n",
    "        # 初始化动量项\n",
    "        delta_wih = np.zeros_like(self.wih)\n",
    "        delta_who = np.zeros_like(self.who)\n",
    "        delta_bih = np.zeros_like(self.bih)\n",
    "        delta_bho = np.zeros_like(self.bho)\n",
    "        while step < self.maxstep:\n",
    "            step += 1\n",
    "            # 向前传播\n",
    "            x_output_out, x_output_in, x_hidden_out, x_hidden_in = self.forward(X_data)\n",
    "            if np.sum(abs(x_output_out - y_data)) < self.epsilon:\n",
    "                break\n",
    "            # 误差反向传播，依据权值逐层计算当层误差\n",
    "            err_output = y_data - x_output_out  # n*o， 输出层上，每个神经元上的误差\n",
    "            delta_ho = -err_output * diff_sigmoid(x_output_in)  # n*o\n",
    "            err_hidden = delta_ho @ self.who.T  # n*h， 隐藏层（相当于输入层的输出），每个神经元上的误差\n",
    "            # 隐藏层到输出层权值及阈值更新\n",
    "            delta_bho = np.sum(self.eta * delta_ho + self.alpha * delta_bho, axis=0) / self.N\n",
    "            self.bho -= delta_bho\n",
    "            delta_who = self.eta * x_hidden_out.T @ delta_ho + self.alpha * delta_who\n",
    "            self.who -= delta_who\n",
    "            # 输入层到隐藏层权值及阈值的更新\n",
    "            delta_ih = err_hidden * diff_sigmoid(x_hidden_in)  # n*h\n",
    "            delta_bih = np.sum(self.eta * delta_ih + self.alpha * delta_bih, axis=0) / self.N\n",
    "            self.bih -= delta_bih\n",
    "            delta_wih = self.eta * X_data.T @ delta_ih + self.alpha * delta_wih\n",
    "            self.wih -= delta_wih\n",
    "        return\n",
    "\n",
    "    def predict(self, X):\n",
    "        # 预测\n",
    "        res = self.forward(X)\n",
    "        return res[0]\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1967b375128>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "if __name__ == '__main__':\n",
    "    \n",
    "\n",
    "    N = 1000\n",
    "    X_data1 = np.random.uniform(-1,1,size=N)\n",
    "    X_data2 = np.random.uniform(-1,1,size=N)\n",
    "    \n",
    "    X_data1 = np.transpose([X_data1])\n",
    "    X_data2 = np.transpose([X_data2])\n",
    "    X_data = np.concatenate((X_data1,X_data2),axis=1)\n",
    "    #print(X_data)\n",
    "   \n",
    "    y_data = [[1,0] if(x[1]*x[0]>0) else [0,1] for x in X_data]\n",
    "    y_data=np.array(y_data)\n",
    "    #print(y_data)\n",
    "    bp = BP(maxstep=2000,  alpha=0.1)  # 注意学习率若过大，将导致不能收敛\n",
    "    bp.fit(X_data, y_data)\n",
    "    #plt.plot(X_data, y_data)\n",
    "    #pred = bp.predict(X_data)\n",
    "    #print(pred)\n",
    "   # plt.scatter(X_data, pred, color='r')\n",
    "    xcord1 = []; ycord1 = []\n",
    "    xcord2 = []; ycord2 = []\n",
    "    xcord3 = []; ycord3 = []\n",
    "    xcord4 = []; ycord4 = []\n",
    "    for i in range(N):\n",
    "        if int(y_data[i][0])== 1:\n",
    "           xcord1.append(X_data[i,0]); ycord1.append(X_data[i,1])\n",
    "        else:\n",
    "             xcord2.append(X_data[i,0]); ycord2.append(X_data[i,1])\n",
    "             \n",
    "             \n",
    "    X_test1 = np.random.uniform(-1,1,size=N)\n",
    "    X_test2 = np.random.uniform(-1,1,size=N)\n",
    "    \n",
    "    X_test1 = np.transpose([X_test1])\n",
    "    X_test2 = np.transpose([X_test2])\n",
    "    X_test = np.concatenate((X_test1,X_test2),axis=1)\n",
    "    y_test = [[1,0] if(x[1]*x[0]>0) else [0,1] for x in X_test]\n",
    "    y_test=np.array(y_test)\n",
    "    #print(y_test,\"sdsdsd\")\n",
    "    pred = bp.predict(X_test)\n",
    "    #print(pred)\n",
    "    fig = plt.figure()\n",
    "    ax = fig.add_subplot(111)\n",
    "    ax.scatter(xcord1, ycord1, s=30, c='red', marker='s')\n",
    "    ax.scatter(xcord2, ycord2, s=30, c='green')\n",
    "    for i in range(N):\n",
    "        #print(pred[i].argmax(),\"aaa\",y_test[i].argmax())\n",
    "        if pred[i].argmax() != y_test[i].argmax() :\n",
    "            xcord3.append(X_test[i,0]); ycord3.append(X_test[i,1])\n",
    "        else:\n",
    "             xcord4.append(X_test[i,0]); ycord4.append(X_test[i,1])\n",
    "                \n",
    "    ax.scatter(xcord3, ycord3, s=30, c='black')\n",
    "    #ax.scatter(xcord4, ycord4, s=30, c='blue')\n",
    "    plt.xlabel('X1'); plt.ylabel('X2');\n",
    "    \n",
    "    plt.show()"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python_ten",
   "language": "python",
   "name": "tf"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
